﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Collections.Concurrent;
using Upreader.Application.Model;
using Upreader.Application;

namespace Upreader.Engine
{
    public class DownloadEngineContext
    {
        #region Fields

        // holds a reference to the underlying service
        private readonly IApplicationService _service;
        private readonly DownloadEngineConfiguration _configuration;

        // data stores
        private readonly SegmentDataStore _segmentDataStore;
        private readonly DownloadDataStore _downloadDataStore;

        // for segments
        private readonly BlockingCollection<DownloadSegmentContext> _unhandeledSegmentContextCollection;
        private readonly BlockingCollection<DownloadSegmentContext> _downloadedSegmentContextCollection;
        private readonly BlockingCollection<Segment> _cachedSegmentContextCollection;

        // for files
        private readonly BlockingCollection<File> _assembledFileCollection;

        // for servers
        private readonly ConcurrentDictionary<int, ServerProcessor> _serverDictionary;

        #endregion // Fields

        #region Constructor

        public DownloadEngineContext(IApplicationService service, DownloadEngineConfiguration configuration)
        {
            if (service == null)
                throw new ArgumentNullException("service");
            if (configuration == null)
                throw new ArgumentNullException("configuration");

            _service = service;
            _configuration = configuration;

            // Setup data containers
            _unhandeledSegmentContextCollection = new BlockingCollection<DownloadSegmentContext>(Configuration.SegmentProcessorCollectionBufferSize);
            _downloadedSegmentContextCollection = new BlockingCollection<DownloadSegmentContext>(Configuration.DownloadedSegmentProcessorCollectionBufferSize);
            _cachedSegmentContextCollection = new BlockingCollection<Segment>(Configuration.DownloadedSegmentProcessorCollectionBufferSize);
            _serverDictionary = new ConcurrentDictionary<int, ServerProcessor>();
            _assembledFileCollection = new BlockingCollection<File>(Configuration.FileAssembleCollectionBufferSize);

            _segmentDataStore = CreateSegmentDataStore();
            _downloadDataStore = CreateDownloadDataStore();
        }

        #endregion // Constructor

        #region Helpers

        protected virtual SegmentDataStore CreateSegmentDataStore()
        {
            return new SegmentDataStore(Configuration.SegmentsInMemoryCache);
        }

        protected virtual DownloadDataStore CreateDownloadDataStore()
        {
            return new DownloadDataStore();
        }

        #endregion // Helpers

        #region Properties

        /// <summary>
        /// Get the applicationService for which this engine was originally constructed
        /// </summary>
        public IApplicationService Service { get { return _service; } }

        /// <summary>
        /// Get the configuration used when running
        /// </summary>
        public DownloadEngineConfiguration Configuration { get { return _configuration; } }

        public BlockingCollection<DownloadSegmentContext> UnhandeledSegmentContextCollection { get { return _unhandeledSegmentContextCollection; } }

        public SegmentDataStore SegmentDataStore { get { return _segmentDataStore; } }

        public DownloadDataStore DownloadDataStore { get { return _downloadDataStore; } }

        public BlockingCollection<DownloadSegmentContext> DownloadedSegmentContextCollection { get { return _downloadedSegmentContextCollection; } }

        public BlockingCollection<Segment> CachedSegmentCollection { get { return _cachedSegmentContextCollection; } }

        public BlockingCollection<File> AssembledFileCollection { get { return _assembledFileCollection; } }

        public ConcurrentDictionary<int, ServerProcessor> ServerDictionary { get { return _serverDictionary; } }

        #endregion // Properties
    }
}
